package cn.scau.server.service.impl;

import cn.scau.server.mapper.EmpMapper;
import cn.scau.server.mapper.EmpPosMapper;
import cn.scau.server.pojo.Attendance;
import cn.scau.server.mapper.AttendanceMapper;
import cn.scau.server.pojo.Emp;
import cn.scau.server.pojo.EmpPos;
import cn.scau.server.service.AttendanceService;
import cn.scau.server.utils.MobileUserHolder;
import cn.scau.server.vo.ResultVO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static cn.scau.server.pojo.Attendance.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 代码不跑我先跑
 * @since 2025-03-30
 */
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class AttendanceServiceImpl extends ServiceImpl<AttendanceMapper, Attendance> implements AttendanceService {
    @Autowired
    private AttendanceMapper attendanceMapper;
    @Autowired
    private EmpMapper empMapper;
    @Autowired
    private EmpPosMapper empPosMapper;

    @Override
    public ResultVO checkInOrOut() {
        String empId= MobileUserHolder.getEmpPermission().getEmpId();
        // 1. 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        LocalDate today = now.toLocalDate();
        LocalTime currentTime = now.toLocalTime();

        // 2. 检查前一天未签退的情况（8:00前处理前一天的签退）
        if (currentTime.isBefore(CHECK_OUT_TIME_END)) {
            return handlePreviousDayCheckOut(empId, now, today.minusDays(1));
        }

        // 2.获取该员工今日记录
        QueryWrapper<Attendance> qw = new QueryWrapper<>();
        qw.eq("emp_id", empId)
                .eq("date", today);
        Attendance record = attendanceMapper.selectOne(qw);
        if (record == null) {
            return ResultVO.fail("签到未开始，请稍后重试");
        }

        // 3.请假、出差：打卡失败
        if (record.getStatus() == 1 || record.getStatus() == 2) {
            return ResultVO.fail("无需打卡");
        }

        // 5. 签到/签退逻辑
        if (record.getCheckInTime() == null) {
            return handleCheckIn(record, now, currentTime);
        } else if (record.getCheckOutTime() == null) {
            return handleCheckOut(record, now, currentTime);
        } else {
            return ResultVO.fail("今日已完成签到和签退");
        }
    }

    // 处理前一天未签退的情况
    private ResultVO handlePreviousDayCheckOut(String empId, LocalDateTime now, LocalDate yesterday) {
        Attendance recordYesterday = attendanceMapper.selectOne(
                new QueryWrapper<Attendance>()
                        .eq("emp_id", empId)
                        .eq("date", yesterday)
        );

        if (recordYesterday == null) {
            return ResultVO.fail("前一天的考勤记录不存在");
        }

        // 只有签到但未签退的情况才允许补签退
        if (recordYesterday.getCheckInTime() != null && recordYesterday.getCheckOutTime() == null) {
            recordYesterday.setCheckOutTime(now);
            recordYesterday.setStatus(calculateCheckOutStatus(recordYesterday, now.toLocalTime(), true));
            attendanceMapper.updateById(recordYesterday);
            return ResultVO.success("前一天签退成功", recordYesterday);
        }

        return ResultVO.fail("无需签退");
    }

    // 处理签到逻辑
    private ResultVO handleCheckIn(Attendance record, LocalDateTime now, LocalTime currentTime) {
        // 检查是否在签到时间段内
        if (currentTime.isBefore(CHECK_IN_TIME_START)) {
            return ResultVO.fail("签到未开始，请于08:30后再试");
        }

        // 检查是否已超过最晚签到时间
        if (currentTime.isAfter(STANDARD_CHECK_OUT_TIME)) {
            return ResultVO.fail("签到失败，已超过最晚签到时间");
        }

        // 执行签到
        record.setCheckInTime(now);
        record.setStatus(currentTime.isAfter(STANDARD_CHECK_IN_TIME) ? 4 : 3); // 4:迟到 3:正常
        attendanceMapper.updateById(record);

        return ResultVO.success("签到成功", record);
    }

    // 处理签退逻辑
    private ResultVO handleCheckOut(Attendance record, LocalDateTime now, LocalTime currentTime) {
        // 执行签退
        record.setCheckOutTime(now);
        record.setStatus(calculateCheckOutStatus(record, currentTime, false));
        attendanceMapper.updateById(record);
        return ResultVO.success("签退成功", record);
    }

    // 计算签退后的状态
    private int calculateCheckOutStatus(Attendance record, LocalTime checkOutTime, boolean isNextDay) {
        int currentStatus = record.getStatus();
        boolean isEarlyLeave = !isNextDay && checkOutTime.isBefore(STANDARD_CHECK_OUT_TIME);

        switch (currentStatus) {
            case 3: // 正常签到
                return isEarlyLeave ? 6 : 8; // 6:早退 8:正常出勤
            case 4: // 迟到
                return isEarlyLeave ? 7 : 4; // 7:部分出勤 4:迟到(保持)
            default:
                return currentStatus; // 其他状态保持不变
        }
    }

    /**
     * 每天上班前40分钟自动创建当天考勤记录
     */
    @Scheduled(cron = "0 20 8 * * ?")  // 8:20
    public void createTodayRecord() {
        LocalDate today = LocalDate.now();
        System.out.println("开始执行每日考勤记录自动创建，日期：" + today);

        // 1. 从emp表获取所有员工ID
        List<String> allEmpIds = empMapper.selectObjs(
                        new QueryWrapper<Emp>()
                                .select("DISTINCT emp_id") // 假设员工ID字段名为emp_id
                ).stream()
                .map(obj -> (String) obj)
                .collect(Collectors.toList());

        if (CollectionUtils.isEmpty(allEmpIds)) {
            System.out.println("员工表中没有员工数据，跳过考勤记录创建");
            return;
        }

        // 2. 查询已有当天考勤记录的所有员工ID
        List<String> existingEmpIds = attendanceMapper.selectObjs(
                        new QueryWrapper<Attendance>()
                                .select("DISTINCT emp_id")
                                .eq("date", today)
                ).stream()
                .map(obj -> (String) obj)
                .collect(Collectors.toList());

        // 3. 找出需要创建记录的员工ID
        List<String> empIdsToCreate = allEmpIds.stream()
                .filter(empId -> !existingEmpIds.contains(empId))
                .collect(Collectors.toList());

        // 4. 批量创建新记录
        if (!empIdsToCreate.isEmpty()) {
            List<Attendance> newRecords = empIdsToCreate.stream()
                    .map(empId -> {
                        Attendance record = new Attendance();
                        record.setEmpId(empId);
                        record.setDate(today);
                        record.setStatus(0); // 默认状态
                        return record;
                    })
                    .collect(Collectors.toList());

            // 批量插入，每批100条
            saveBatch(newRecords, 100);
            System.out.println("成功创建考勤记录：" + newRecords.size());
        } else {
            System.out.println("所有员工已有当天的考勤记录，无需创建");
        }
    }

    /**
     * 下班前1小时，对于出差请假以外的员工，未签到的改为旷工
     */
    @Scheduled(cron = "0 0 16 * * ?") // 每天16:00执行（秒，分，时，日，月，星期）
    public void markAbsenteeism() {
        LocalDate today = LocalDate.now();
        System.out.println("开始执行每日旷工登记，日期：" + today);

        // 1. 查询所有今天未签到且不是请假/出差的记录
        QueryWrapper<Attendance> queryWrapper = new QueryWrapper<>();
        queryWrapper.isNull("check_in_time")    // 未签到
                .ne("status", 1)           // 不是请假
                .ne("status", 2)           // 不是出差
                .eq("date", today);             // 今天的记录

        List<Attendance> absentRecords = attendanceMapper.selectList(queryWrapper);

        // 2. 将这些记录状态改为旷工(5)
        if (!absentRecords.isEmpty()) {
            absentRecords.forEach(record -> {
                record.setStatus(5); // 旷工
                attendanceMapper.updateById(record);
            });
            System.out.println("下班前1小时自动标记旷工处理完成，共处理记录: " + absentRecords.size());
        }
    }

    @Override
    public ResultVO getPersonalAttendance(String start, String end) {
        String empId= MobileUserHolder.getEmpPermission().getEmpId();
        // 1. 参数校验
        LocalDate startDate, endDate;
        if (start.isEmpty()) {
            startDate = LocalDate.of(1900, 1, 1);
        } else {
            startDate = LocalDate.parse(start);
        }

        if (end.isEmpty()) {
            endDate = LocalDate.now();
        } else {
            endDate = LocalDate.parse(end);
        }

        if (startDate.isAfter(endDate)) {
            return ResultVO.fail("开始日期不能晚于结束日期");
        }

        // 2. 构建查询条件
        QueryWrapper<Attendance> qw = new QueryWrapper<>();
        qw.eq("emp_id", empId);
        qw.between("date", startDate, endDate);
        qw.orderByDesc("date");

        // 3. 构建返回结果
        List<Attendance> result = attendanceMapper.selectList(qw);

        return ResultVO.success("查询成功", result);
    }

    @Override
    public ResultVO recordTripOrLeave(String empId, LocalDate date, Integer status) {
        System.out.println("进入recordTripOrLeave方法");
        if(status!=1&&status!=2){
            System.out.println("状态参数错误");
            return ResultVO.fail("状态参数错误");
        }
        // 获取该员工该日记录
        QueryWrapper<Attendance> qw = new QueryWrapper<>();
        qw.eq("emp_id", empId)
                .eq("date", date);
        System.out.println("准备查记录");
        Attendance record = attendanceMapper.selectOne(qw);
//        System.out.println("record: "+record.toString());
        // 没有记录就创建
        if (record == null) {
            System.out.println("没有当日记录，创建中");
            record = new Attendance();
            record.setEmpId(empId);
            record.setDate(date);
            record.setStatus(status);
            attendanceMapper.insert(record);
        }else{
            record.setStatus(status);
            attendanceMapper.updateById(record);
        }
        System.out.println("记录成功");
        return ResultVO.success("记录成功", record);
    }

    @Override
    public ResultVO repair(String empId, LocalDate date, Integer repairType, LocalDateTime repairTime) {
//        System.out.println("进入repair方法");
        LocalDateTime now=LocalDateTime.now();
        if(repairTime.isAfter(now)){
//            System.out.println("补卡时间不得晚于当前时间");
            ResultVO.fail("补卡时间不得晚于当前时间");
        }

        boolean isNextDay;
        LocalDate repairDate=repairTime.toLocalDate();
        LocalTime time=repairTime.toLocalTime();
//        System.out.println("repairDate: "+repairDate);
//        System.out.println("date: "+date);
        if(repairDate.equals(date)){
            isNextDay=false;
        }else if(repairDate.minusDays(1)==date){
            if(time.isAfter(CHECK_OUT_TIME_END)){
//                System.out.println("已超过签退时间");
                return ResultVO.fail("已超过签退时间");
            }
            isNextDay=true;
        }else{
            System.out.println("日期与时间不对应");
            return ResultVO.fail("日期与时间不对应");
        }

        // 获取该员工该日记录
        QueryWrapper<Attendance> qw = new QueryWrapper<>();
        qw.eq("emp_id", empId)
                .eq("date", date);
        Attendance record = attendanceMapper.selectOne(qw);
        // 没有记录就创建
        if (record == null) {
            record = new Attendance();
            record.setEmpId(empId);
            record.setDate(date);
        }
        // 记录补卡数据
        if(repairType==1){  // 补签到
            System.out.println("补签到中");
            if(time.isBefore(CHECK_IN_TIME_START)||time.isAfter(STANDARD_CHECK_OUT_TIME)){
                ResultVO.fail("补签到时间不在签到时间范围内");
            }
            if(record.getCheckOutTime()!=null&&record.getCheckOutTime().isBefore(repairTime)){
                ResultVO.fail("签到时间不能晚于签退时间");
            }
            record.setRepairIn(true);
            record.setCheckInTime(repairTime);
            record.setStatus(time.isAfter(STANDARD_CHECK_IN_TIME) ? 4 : 3); // 4:迟到 3:正常
            attendanceMapper.updateById(record);
//            System.out.println("补签到成功");
            return ResultVO.success("补签到成功", record);
        }else if(repairType==2){
            if(record.getCheckInTime()==null){
                ResultVO.fail("当天未签到，不能签退");
            }
            if(record.getCheckInTime().isAfter(repairTime)){
                ResultVO.fail("签退时间不能早于签到时间");
            }
            record.setRepairOut(true);
            record.setCheckOutTime(repairTime);
            record.setStatus(calculateCheckOutStatus(record, time, isNextDay));
            attendanceMapper.updateById(record);
            return ResultVO.success("补签退成功", record);
        }
        return ResultVO.fail("补卡类型错误");
    }

    @Override
    public ResultVO getDeptAttendance(String startDate, String endDate, Integer deptId, String underEmpId) {
        String currentEmpId= MobileUserHolder.getEmpPermission().getEmpId();

        // 1. 检查当前员工是否是领导
        QueryWrapper<EmpPos> leaderQw = new QueryWrapper<>();
        leaderQw.eq("emp_id", currentEmpId)
                .eq("is_leader", 1);
        EmpPos empPos = empPosMapper.selectOne(leaderQw);

        if (empPos == null || empPos.getIsLeader()!=1) {
            return ResultVO.fail("无权限查看部门考勤记录");
        }

        // 2. 处理日期参数
        LocalDate start, end;
        try {
            start = startDate == null || startDate.isEmpty() ? LocalDate.of(1900, 1, 1) : LocalDate.parse(startDate);
            end = endDate == null || endDate.isEmpty() ? LocalDate.now() : LocalDate.parse(endDate);

            if (start.isAfter(end)) {
                return ResultVO.fail("开始日期不能晚于结束日期");
            }
        } catch (Exception e) {
            return ResultVO.fail("日期格式错误，请使用yyyy-MM-dd格式");
        }

        // 3. 获取要查询的员工ID列表
        List<String> empIdsToQuery = new ArrayList<>();

        if (underEmpId != null && !underEmpId.isEmpty()) {
            // 查询指定员工
            empIdsToQuery.add(underEmpId);
        } else {
            // 仅查询当前部门的所有员工（不包含子部门）
            QueryWrapper<EmpPos> empQw = new QueryWrapper<>();
            empQw.eq("dept_id", deptId)  // 仅查询当前部门
                    .select("DISTINCT emp_id");
            List<EmpPos> empPosList = empPosMapper.selectList(empQw);

            if (!CollectionUtils.isEmpty(empPosList)) {
                empIdsToQuery.addAll(empPosList.stream()
                        .map(EmpPos::getEmpId)
                        .toList());
            }
        }

        if (empIdsToQuery.isEmpty()) {
            return ResultVO.success("没有可查询的员工", new ArrayList<>());
        }

        // 4. 查询考勤记录
        QueryWrapper<Attendance> attendanceQw = new QueryWrapper<>();
        attendanceQw.in("emp_id", empIdsToQuery)
                .between("date", start, end)
                .orderByDesc("date")
                .orderByAsc("emp_id");

        List<Attendance> records = attendanceMapper.selectList(attendanceQw);
        return ResultVO.success("查询成功", records);
    }
}
